home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / jove4.9 / part07 < prev    next >
Encoding:
Internet Message Format  |  1988-04-25  |  46.0 KB

  1. Subject:  v14i063:  Jove, an emacs variant, version 4.9, Part07/21
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
  7. Posting-number: Volume 14, Issue 63
  8. Archive-name: jove4.9/part07
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 7 (of 21)."
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f './c.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'./c.c'\"
  20. else
  21. echo shar: Extracting \"'./c.c'\" \(14160 characters\)
  22. sed "s/^X//" >'./c.c' <<'END_OF_FILE'
  23. X/***************************************************************************
  24. X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  25. X * is provided to you without charge, and with no warranty.  You may give  *
  26. X * away copies of JOVE, including sources, provided that this notice is    *
  27. X * included in all the files.                                              *
  28. X ***************************************************************************/
  29. X
  30. X/* Contains commands for C mode.  Paren matching routines are in here. */
  31. X
  32. X#include "jove.h"
  33. X#include "re.h"
  34. X#include "ctype.h"
  35. X
  36. X#ifdef MAC
  37. X#    undef private
  38. X#    define private
  39. X#endif
  40. X
  41. X#ifdef    LINT_ARGS
  42. private int
  43. X    backslashed(char *, int);
  44. private void    
  45. X    do_expr(int, int),
  46. X    FindMatch(int),
  47. X    parse_cmt_fmt(char *),
  48. X    strip_c(char *, char *);
  49. X#else
  50. private int
  51. X    backslashed();
  52. private void    
  53. X    do_expr(),
  54. X    FindMatch(),
  55. X    parse_cmt_fmt(),
  56. X    strip_c();
  57. X#endif    /* LINT_ARGS */
  58. X
  59. X#ifdef MAC
  60. X#    undef private
  61. X#    define private static
  62. X#endif
  63. X
  64. X
  65. private int
  66. backslashed(lp, cpos)
  67. register char    *lp;
  68. register int    cpos;
  69. X{
  70. X    register int    cnt = 0;
  71. X
  72. X    while (cpos > 0 && lp[--cpos] == '\\')
  73. X        cnt += 1;
  74. X    return (cnt % 2);
  75. X}
  76. X
  77. private char    *p_types = "(){}[]";
  78. private int    mp_kind;
  79. X#define MP_OKAY        0
  80. X#define MP_MISMATCH    1
  81. X#define MP_UNBALANCED    2
  82. X
  83. void
  84. mp_error()
  85. X{
  86. X    switch (mp_kind) {
  87. X    case MP_MISMATCH:
  88. X        message("[Mismatched parentheses]");
  89. X        break;
  90. X
  91. X    case MP_UNBALANCED:
  92. X        message("[Unbalanced parenthesis]");
  93. X        break;
  94. X
  95. X    case MP_OKAY:
  96. X    default:
  97. X        return;
  98. X    }
  99. X    rbell();
  100. X}
  101. X
  102. X/* Search from the current position for the paren that matches p_type.
  103. X   Search in the direction dir.  If can_mismatch is YES then it is okay
  104. X   to have mismatched parens.  If stop_early is YES then when an open
  105. X   paren is found at the beginning of a line, it is assumed that there
  106. X   is no point in backing up further.  This is so when you hit tab or
  107. X   LineFeed outside, in-between procedure/function definitions, it won't
  108. X   sit there searching all the way to the beginning of the file for a
  109. X   match that doesn't exist.  {forward,backward}-s-expression are the
  110. X   only ones that insist on getting the "true" story. */
  111. X
  112. Bufpos *
  113. m_paren(p_type, dir, can_mismatch, can_stop)
  114. char    p_type;
  115. register int    dir;
  116. X{
  117. X    static Bufpos    ret;
  118. X    Bufpos    savedot,
  119. X        *sp;
  120. X    char    re_buf[100],
  121. X        *re_alts[NALTS];
  122. X    int    count = 0;
  123. X    register char    *lp,
  124. X            c;
  125. X    char    p_match,
  126. X        re_str[128],
  127. X        *cp,
  128. X        quote_c = 0;
  129. X    register int    c_char;
  130. X    int    in_comment = -1,
  131. X        stopped = NO;
  132. X
  133. X    sprintf(re_str, "[(){}[\\]%s]", (MajorMode(CMODE)) ? "/\"'" : "\"");
  134. X    REcompile(re_str, 1, re_buf, re_alts);
  135. X    if (cp = index(p_types, p_type))
  136. X        p_match = cp[dir];
  137. X    else
  138. X        complain("[Cannot match %c's]", p_type);
  139. X    DOTsave(&savedot);
  140. X
  141. X    /* To make things a little faster I avoid copying lines into
  142. X       linebuf by setting curline and curchar by hand.  Warning:
  143. X       this is slightly to very risky.  When I did this there were
  144. X       lots of problems with procedures that expect the contents of
  145. X       curline to be in linebuf. */
  146. X    while (count >= 0) {
  147. X        sp = docompiled(dir, re_buf, re_alts);
  148. X        if (sp == 0)
  149. X            break;
  150. X        lp = lbptr(sp->p_line);
  151. X
  152. X        if (sp->p_line != curline)
  153. X            /* let's assume that strings do NOT go over line
  154. X               bounderies (for now don't check for wrapping
  155. X                strings) */
  156. X            quote_c = 0;
  157. X        curline = sp->p_line;
  158. X        curchar = sp->p_char;    /* here's where I cheat */
  159. X        c_char = curchar;
  160. X        if (dir == FORWARD)
  161. X            c_char -= 1;
  162. X        if (backslashed(lp, c_char))
  163. X            continue;
  164. X        c = lp[c_char];
  165. X        /* check if this is a comment (if we're not inside quotes) */
  166. X        if (quote_c == 0 && c == '/') {
  167. X            int    new_ic;
  168. X
  169. X            if ((c_char != 0) && lp[c_char - 1] == '*') {
  170. X                new_ic = (dir == FORWARD) ? NO : YES;
  171. X                if (new_ic == NO && in_comment == -1) {
  172. X                    count = 0;
  173. X                    quote_c = 0;
  174. X                }
  175. X            } else if (lp[c_char + 1] == '*') {
  176. X                new_ic = (dir == FORWARD) ? YES : NO;
  177. X                if (new_ic == NO && in_comment == -1) {
  178. X                    count = 0;
  179. X                    quote_c = 0;
  180. X                }
  181. X            }
  182. X            in_comment = new_ic;
  183. X        }
  184. X        if (in_comment == YES)
  185. X            continue;
  186. X        if (c == '"' || c == '\'') {
  187. X            if (quote_c == c)
  188. X                quote_c = 0;
  189. X            else if (quote_c == 0)
  190. X                quote_c = c;
  191. X        }
  192. X        if (quote_c != 0)
  193. X            continue;
  194. X        if (isopenp(c)) {
  195. X            count += dir;
  196. X            if (c_char == 0 && can_stop == YES && count >= 0) {
  197. X                stopped = YES;
  198. X                break;
  199. X            }
  200. X        } else if (isclosep(c))
  201. X            count -= dir;
  202. X    }
  203. X
  204. X    ret.p_line = curline;
  205. X    ret.p_char = curchar;
  206. X
  207. X    curline = savedot.p_line;
  208. X    curchar = savedot.p_char;    /* here's where I undo it */
  209. X
  210. X    if (count >= 0)
  211. X        mp_kind = MP_UNBALANCED;
  212. X    else if (c != p_match)
  213. X        mp_kind = MP_MISMATCH;
  214. X    else
  215. X        mp_kind = MP_OKAY;
  216. X
  217. X    /* If we stopped (which means we were allowed to stop) and there
  218. X       was an error, we clear the error so no error message is printed.
  219. X       An error should be printed ONLY when we are sure about the fact,
  220. X       namely we didn't stop prematurely HOPING that it was the right
  221. X       answer. */
  222. X    if (stopped && mp_kind != MP_OKAY) {
  223. X        mp_kind = MP_OKAY;
  224. X        return 0;
  225. X    }
  226. X    if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
  227. X        return &ret;
  228. X    return 0;
  229. X}
  230. X
  231. private void
  232. do_expr(dir, skip_words)
  233. register int    dir;
  234. X{
  235. X    register char    c,
  236. X            syntax = (dir == FORWARD) ? _Op : _Cl;
  237. X
  238. X    if (dir == BACKWARD)
  239. X        b_char(1);
  240. X    c = linebuf[curchar];
  241. X    for (;;) {
  242. X        if (!skip_words && ismword(c)) {
  243. X            WITH_TABLE(curbuf->b_major)
  244. X            if(dir == FORWARD) f_word(1);
  245. X                else b_word(1);    
  246. X            END_TABLE();
  247. X            break;
  248. X        } else if (has_syntax(c, syntax)) {
  249. X            FindMatch(dir);
  250. X            break;
  251. X        }
  252. X        f_char(dir);
  253. X        if (eobp() || bobp())
  254. X            return;
  255. X        c = linebuf[curchar];
  256. X    }
  257. X}
  258. X
  259. void
  260. FSexpr()
  261. X{
  262. X    register int    num = arg_value();
  263. X
  264. X    if (num < 0) {
  265. X        set_arg_value(-num);
  266. X        BSexpr();
  267. X    }
  268. X    while (--num >= 0)
  269. X        do_expr(FORWARD, NO);
  270. X}
  271. X
  272. void
  273. FList()
  274. X{
  275. X    register int    num = arg_value();
  276. X
  277. X    if (num < 0) {
  278. X        set_arg_value(-num);
  279. X        BList();
  280. X    }
  281. X    while (--num >= 0)
  282. X        do_expr(FORWARD, YES);
  283. X}
  284. X
  285. void
  286. BSexpr()
  287. X{
  288. X    register int    num = arg_value();
  289. X
  290. X    if (num < 0) {
  291. X        negate_arg_value();
  292. X        FSexpr();
  293. X    }
  294. X    while (--num >= 0)
  295. X        do_expr(BACKWARD, NO);
  296. X}
  297. X
  298. void
  299. BList()
  300. X{
  301. X    register int    num = arg_value();
  302. X
  303. X    if (num < 0) {
  304. X        negate_arg_value();
  305. X        FList();
  306. X    }
  307. X    while (--num >= 0)
  308. X        do_expr(BACKWARD, YES);
  309. X}
  310. X
  311. void
  312. BUpList()
  313. X{
  314. X    Bufpos    *mp;
  315. X    char    c = (MajorMode(CMODE) ? '}' : ')');
  316. X
  317. X    mp = m_paren(c, BACKWARD, NO, YES);
  318. X    if (mp == 0)
  319. X        mp_error();
  320. X    else
  321. X        SetDot(mp);
  322. X}
  323. X
  324. void
  325. FDownList()
  326. X{
  327. X    Bufpos    *sp;
  328. X    char    *sstr = (MajorMode(CMODE) ? "[{([\\])}]" : "[()]"),
  329. X        *lp;
  330. X
  331. X    sp = dosearch(sstr, FORWARD, YES);
  332. X    if (sp != 0)
  333. X        lp = lcontents(sp->p_line);
  334. X    if (sp == 0 || has_syntax(lp[sp->p_char - 1], _Cl))
  335. X        complain("[No contained expression]");
  336. X    SetDot(sp);
  337. X}
  338. X
  339. X/* Move to the matching brace or paren depending on the current position
  340. X   in the buffer. */
  341. X
  342. private void
  343. FindMatch(dir)
  344. X{
  345. X    register Bufpos    *bp;
  346. X    register char    c = linebuf[curchar];
  347. X
  348. X    if ((index(p_types, c) == 0) ||
  349. X        (backslashed(linebuf, curchar)))
  350. X        complain((char *) 0);
  351. X    if (dir == FORWARD)
  352. X        f_char(1);
  353. X    bp = m_paren(c, dir, YES, NO);
  354. X    if (dir == FORWARD)
  355. X        b_char(1);
  356. X    if (bp != 0)
  357. X        SetDot(bp);
  358. X    mp_error();    /* if there is an error the user wants to
  359. X               know about it */
  360. X}
  361. X
  362. Bufpos *
  363. c_indent(incrmt)
  364. X{
  365. X    Bufpos    *bp;
  366. X    int    indent = 0;
  367. X
  368. X    if (bp = m_paren('}', BACKWARD, NO, YES)) {
  369. X        Bufpos    save;
  370. X
  371. X        DOTsave(&save);
  372. X        SetDot(bp);
  373. X        ToIndent();
  374. X        indent = calc_pos(linebuf, curchar);
  375. X        SetDot(&save);
  376. X    }
  377. X    if (incrmt) {
  378. X        if (indent == 0)
  379. X            incrmt = tabstop;
  380. X        else
  381. X            incrmt = (tabstop - (indent%tabstop));
  382. X    }
  383. X    n_indent(indent + incrmt);
  384. X    return bp;
  385. X}
  386. X
  387. X#ifdef CMT_FMT
  388. X
  389. char    CmtFmt[80] = "/*%n%! * %c%!%n */";
  390. X
  391. void
  392. Comment()
  393. X{
  394. X    FillComment(CmtFmt);
  395. X}
  396. X
  397. X/* Strip leading and trailing white space.  Skip over any imbedded '\r's. */
  398. X
  399. private void
  400. strip_c(from, to)
  401. char    *from,
  402. X    *to;
  403. X{
  404. X    register char    *fr_p = from,
  405. X            *to_p = to,
  406. X            c;
  407. X
  408. X    while (c = *fr_p) {
  409. X        if (c == ' ' || c == '\t' || c == '\r')
  410. X            fr_p += 1;
  411. X        else
  412. X            break;
  413. X    }
  414. X    while (c = *fr_p) {
  415. X        if (c != '\r')
  416. X            *to_p++ = c;
  417. X        fr_p += 1;
  418. X    }
  419. X    while (--to_p >= to)
  420. X        if (*to_p != ' ' && *to_p != '\t')
  421. X            break;
  422. X    *++to_p = '\0';
  423. X}
  424. X
  425. private char    open_c[20],    /* the open comment format string */
  426. X        open_pat[20],    /* the search pattern for open comment */
  427. X        l_header[20],    /* the prefix for each comment line */
  428. X        l_trailer[20],    /* the suffix ... */
  429. X        close_c[20],
  430. X        close_pat[20];
  431. X
  432. private char    *comment_body[] = {
  433. X     open_c,
  434. X    l_header,
  435. X    l_trailer,
  436. X    close_c
  437. X};
  438. X                    
  439. private int    nlflags;
  440. X
  441. X/* Fill in the data structures above from the format string.  Don't return
  442. X   if there's trouble. */
  443. X
  444. private void
  445. parse_cmt_fmt(str)
  446. char    *str;
  447. X{
  448. X    register char    *fmtp = str;
  449. X    register char    **c_body = comment_body,
  450. X            *body_p = *c_body;
  451. X    int    c,
  452. X         newlines = 1;
  453. X
  454. X    /* pick apart the comment string */
  455. X    while (c = *fmtp++) {
  456. X        if (c != '%') {
  457. X            *body_p++ = c;
  458. X            continue;
  459. X        }
  460. X        switch(c = *fmtp++) {
  461. X        case 'n':
  462. X            if (newlines == 2 || newlines == 3)
  463. X                complain("%n not allowed in line header or trailer: %s",
  464. X                  fmtp - 2);
  465. X            nlflags += newlines;
  466. X            *body_p++ = '\r';
  467. X            break;
  468. X        case 't':
  469. X            *body_p++ = '\t';
  470. X            break;
  471. X        case '%':
  472. X            *body_p++ = '%';
  473. X            break;
  474. X        case '!':
  475. X        case 'c':
  476. X            newlines += 1;
  477. X            *body_p++ = '\0';
  478. X            body_p = *++c_body;
  479. X            break;
  480. X        default:
  481. X            complain("[Unknown comment escape: %%%c]", c);
  482. X            /* VARARGS */
  483. X            break;
  484. X        }
  485. X    }
  486. X    *body_p = '\0';
  487. X    /* make search patterns */
  488. X    strip_c(open_c, open_pat);
  489. X    strip_c(close_c, close_pat);
  490. X}
  491. X
  492. X#define NL_IN_OPEN_C  ((nlflags % 4) == 1)
  493. X#define NL_IN_CLOSE_C (nlflags >= 4)
  494. X
  495. void
  496. FillComment(format)
  497. char    *format;
  498. X{
  499. X    int    saveRMargin,
  500. X        indent_pos,
  501. X        close_at_dot = NO,
  502. X        slen,
  503. X        header_len,
  504. X        trailer_len;
  505. X    register char    *cp;
  506. X    static char    inside_err[] = "[Must be between %s and %s to re-format]";
  507. X    Bufpos    open_c_pt,
  508. X        close_c_pt,
  509. X        tmp_bp,
  510. X        *match_o,
  511. X        *match_c;
  512. X    Mark    *entry_mark,
  513. X        *open_c_mark,
  514. X        *savedot;
  515. X
  516. X    parse_cmt_fmt(format);
  517. X    /* figure out if we're "inside" a comment */
  518. X     if ((match_o = dosearch(open_pat, BACKWARD, 0)) == 0)
  519. X        /* VARARGS */
  520. X        complain("No opening %s to match to.", open_pat);
  521. X    open_c_pt = *match_o;
  522. X    if ((match_c = dosearch(close_pat, BACKWARD, NO)) != 0 &&
  523. X        inorder(open_c_pt.p_line, open_c_pt.p_char,
  524. X            match_c->p_line, match_c->p_char))
  525. X          complain(inside_err, open_pat, close_pat);
  526. X    if ((match_o = dosearch(open_pat, FORWARD, NO)) != 0) {
  527. X        tmp_bp = *match_o;
  528. X        match_o = &tmp_bp;
  529. X    } 
  530. X    if ((match_c = dosearch(close_pat, FORWARD, 0)) != (Bufpos *) 0)
  531. X        close_c_pt = *match_c;
  532. X
  533. X    /* Here's where we figure out whether to format from dot or from
  534. X       the close comment.  Note that we've already searched backwards to
  535. X       find the open comment symbol for the comment we are formatting.
  536. X       The open symbol mentioned below refers to the possible existence
  537. X       of the next comment.  There are 5 cases:
  538. X        1) no open or close symbol        ==> dot
  539. X        2) open, but no close symbol        ==> dot
  540. X        3) close, but no open            ==> close
  541. X        4) open, close are inorder        ==> dot
  542. X        5) open, close are not inorder        ==> close */
  543. X
  544. X
  545. X    if (match_o == (Bufpos *) 0) {
  546. X        if (match_c == (Bufpos *) 0)
  547. X            close_at_dot = YES;
  548. X    } else if (match_c == (Bufpos *) 0)
  549. X        close_at_dot = YES;
  550. X    else if (inorder(match_o->p_line, match_o->p_char,
  551. X         match_c->p_line, match_c->p_char))
  552. X        close_at_dot = YES;
  553. X    if (close_at_dot) {
  554. X        close_c_pt.p_line = curline;
  555. X        close_c_pt.p_char = curchar;
  556. X    } else {
  557. X        SetDot(match_c);
  558. X    }
  559. X    SetDot(&open_c_pt);
  560. X    open_c_mark = MakeMark(curline, curchar, M_FLOATER);
  561. X    indent_pos = calc_pos(linebuf, curchar);
  562. X    /* search for a close comment; delete it if it exits */
  563. X    SetDot(&close_c_pt);
  564. X    if (close_at_dot == 0) {
  565. X        slen = strlen(close_pat);
  566. X        while (slen--)
  567. X            del_char(BACKWARD, 1);
  568. X    }
  569. X    entry_mark = MakeMark(curline, curchar, M_FLOATER);
  570. X    ToMark(open_c_mark);
  571. X    /* always separate the comment body from anything preceeding it */
  572. X    LineInsert(1);
  573. X    DelWtSpace();
  574. X    Bol();
  575. X    for (cp = open_c; *cp; cp++) {
  576. X        if (*cp == '\r') {
  577. X            if (!eolp())
  578. X                LineInsert(1);
  579. X            else
  580. X                line_move(FORWARD, 1, NO);
  581. X        } else if (*cp == ' ' || *cp == '\t') {
  582. X            if (linebuf[curchar] != *cp)
  583. X                insert_c(*cp, 1);
  584. X        } else
  585. X            /* Since we matched the open comment string on this
  586. X               line, we don't need to worry about crossing line
  587. X               boundaries. */
  588. X            curchar += 1;
  589. X    }
  590. X    savedot = MakeMark(curline, curchar, M_FLOATER);
  591. X
  592. X    /* We need to strip the line header pattern of leading white space
  593. X       since we need to match the line after all of its leading
  594. X       whitespace is gone. */
  595. X    for (cp = l_header; *cp && (isspace(*cp)); cp++)
  596. X        ;
  597. X    header_len = strlen(cp);
  598. X    trailer_len = strlen(l_trailer);
  599. X
  600. X    /* Strip each comment line of the open and close comment strings
  601. X       before reformatting it. */
  602. X
  603. X    do {
  604. X        Bol();
  605. X        DelWtSpace();
  606. X        if (header_len && !strncmp(linebuf, cp, header_len))
  607. X            del_char(FORWARD, header_len);
  608. X        if (trailer_len) {
  609. X            Eol();
  610. X            if ((curchar > trailer_len) &&
  611. X                (!strncmp(&linebuf[curchar - trailer_len],
  612. X                      l_trailer, trailer_len)))
  613. X                del_char(BACKWARD, trailer_len);
  614. X        }
  615. X        if (curline->l_next != 0)
  616. X            line_move(FORWARD, 1, NO);
  617. X        else
  618. X            break;
  619. X    } while (curline != entry_mark->m_line->l_next);
  620. X
  621. X    do_set_mark(savedot->m_line, savedot->m_char);
  622. X    ToMark(entry_mark);
  623. X    saveRMargin = RMargin;
  624. X    RMargin = saveRMargin - strlen(l_header) -
  625. X          strlen(l_trailer) - indent_pos + 2;
  626. X    do_rfill(NO);
  627. X    RMargin = saveRMargin;
  628. X    /* get back to the start of the comment */
  629. X    PopMark(); 
  630. X    do {
  631. X        if (curline == open_c_mark->m_line->l_next) {
  632. X            ;
  633. X        } else {
  634. X            n_indent(indent_pos);
  635. X            ins_str(l_header, NO);
  636. X        }
  637. X        Eol();
  638. X        if (!NL_IN_CLOSE_C && (curline == entry_mark->m_line))
  639. X            ;
  640. X        else
  641. X            ins_str(l_trailer, NO);
  642. X        if (curline->l_next != 0)
  643. X            line_move(FORWARD, 1, NO);
  644. X        else 
  645. X            break;
  646. X    } while (curline != entry_mark->m_line->l_next);
  647. X    /* handle the close comment symbol */
  648. X    if (curline == entry_mark->m_line->l_next) {
  649. X        line_move(BACKWARD, 1, NO);
  650. X        Eol();
  651. X    }
  652. X    DelWtSpace();
  653. X    /* if the addition of the close symbol would cause the line to be
  654. X       too long, put the close symbol on the next line. */
  655. X    if (!(NL_IN_CLOSE_C) &&
  656. X      strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
  657. X        LineInsert(1);
  658. X        n_indent(indent_pos);
  659. X    }
  660. X    for (cp = close_c; *cp; cp++) {
  661. X        if (*cp == '\r') {
  662. X            LineInsert(1);
  663. X            n_indent(indent_pos);
  664. X        } else
  665. X            insert_c(*cp, 1);
  666. X    }
  667. X    ToMark(open_c_mark);
  668. X    Eol();
  669. X    del_char(FORWARD, 1);
  670. X}
  671. X
  672. X#endif /* CMT_FMT */
  673. X
  674. END_OF_FILE
  675. if test 14160 -ne `wc -c <'./c.c'`; then
  676.     echo shar: \"'./c.c'\" unpacked with wrong size!
  677. fi
  678. # end of './c.c'
  679. fi
  680. if test -f './insert.c' -a "${1}" != "-c" ; then 
  681.   echo shar: Will not clobber existing file \"'./insert.c'\"
  682. else
  683. echo shar: Extracting \"'./insert.c'\" \(14465 characters\)
  684. sed "s/^X//" >'./insert.c' <<'END_OF_FILE'
  685. X/***************************************************************************
  686. X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  687. X * is provided to you without charge, and with no warranty.  You may give  *
  688. X * away copies of JOVE, including sources, provided that this notice is    *
  689. X * included in all the files.                                              *
  690. X ***************************************************************************/
  691. X
  692. X#include "jove.h"
  693. X#include "ctype.h"
  694. X#include "table.h"
  695. X
  696. X#ifdef MAC
  697. X#    undef private
  698. X#    define private
  699. X#endif
  700. X
  701. X#ifdef    LINT_ARGS
  702. private int
  703. X    newchunk(void);
  704. private void    
  705. X    init_specials(void),
  706. X    remfreelines(struct chunk *);
  707. X#else
  708. private int
  709. X    newchunk();
  710. private void    
  711. X    init_specials(),
  712. X    remfreelines();
  713. X#endif    /* LINT_ARGS */
  714. X
  715. X#ifdef MAC
  716. X#    undef private
  717. X#    define private static
  718. X#endif
  719. X
  720. X/* Make a newline after AFTER in buffer BUF, UNLESS after is 0,
  721. X   in which case we insert the newline before after. */
  722. X
  723. Line *
  724. listput(buf, after)
  725. register Buffer    *buf;
  726. register Line    *after;
  727. X{
  728. X    register Line    *newline = nbufline();
  729. X
  730. X    if (after == 0) {    /* Before the first line */
  731. X        newline->l_next = buf->b_first;
  732. X        newline->l_prev = 0;
  733. X        buf->b_first = newline;
  734. X    } else {
  735. X        newline->l_prev = after;
  736. X        newline->l_next = after->l_next;
  737. X        after->l_next = newline;
  738. X    }
  739. X    if (newline->l_next)
  740. X        newline->l_next->l_prev = newline;
  741. X    else
  742. X        if (buf)
  743. X            buf->b_last = newline;
  744. X    if (buf && buf->b_dot == 0)
  745. X        buf->b_dot = newline;
  746. X    return newline;
  747. X}    
  748. X
  749. X/* Divide the current line and move the current line to the next one */
  750. X
  751. void
  752. LineInsert(num)
  753. register int    num;
  754. X{
  755. X    char    newline[LBSIZE];
  756. X    register Line    *newdot,
  757. X            *olddot;
  758. X    int    oldchar;
  759. X
  760. X    olddot = curline;
  761. X    oldchar = curchar;
  762. X
  763. X    newdot = curline;
  764. X    while (--num >= 0) {
  765. X        newdot = listput(curbuf, newdot);
  766. X        SavLine(newdot, NullStr);
  767. X    }
  768. X
  769. X    modify();
  770. X    if (curchar != 0) {
  771. X        strcpy(newline, &linebuf[curchar]);
  772. X        linebuf[curchar] = '\0';    /* Shorten this line */
  773. X        SavLine(curline, linebuf);
  774. X        strcpy(linebuf, newline);
  775. X    } else {    /* Redisplay optimization */
  776. X        newdot->l_dline = curline->l_dline;
  777. X        SavLine(curline, NullStr);
  778. X    }
  779. X
  780. X    makedirty(curline);
  781. X    curline = newdot;
  782. X    curchar = 0;
  783. X    makedirty(curline);
  784. X    IFixMarks(olddot, oldchar, curline, curchar);
  785. X}    
  786. X
  787. X/* Makes the indent of the current line == goal.  If the current indent
  788. X   is greater than GOAL it deletes.  If more indent is needed, it uses
  789. X   tabs and spaces to get to where it's going. */
  790. X
  791. void
  792. n_indent(goal)
  793. register int    goal;
  794. X{
  795. X    int    dotcol,
  796. X        incrmt;
  797. X
  798. X    ToIndent();
  799. X    dotcol = calc_pos(linebuf, curchar);
  800. X    if (goal < dotcol) {
  801. X        DelWtSpace();
  802. X        dotcol = 0;
  803. X    }
  804. X
  805. X    for (;;) {
  806. X        incrmt = (tabstop - (dotcol % tabstop));
  807. X        if (dotcol + incrmt > goal)
  808. X            break;
  809. X        insert_c('\t', 1);
  810. X        dotcol += incrmt;
  811. X    }
  812. X    if (dotcol != goal)
  813. X        insert_c(' ', (goal - dotcol));
  814. X}
  815. X
  816. X#ifdef ABBREV
  817. void
  818. MaybeAbbrevExpand()
  819. X{
  820. X    if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
  821. X        !bolp() && ismword(linebuf[curchar - 1]))
  822. X        AbbrevExpand();
  823. X}
  824. X#endif
  825. X
  826. void
  827. SelfInsert()
  828. X{
  829. X#ifdef ABBREV
  830. X    MaybeAbbrevExpand();
  831. X#endif
  832. X    if (LastKeyStruck != CTL('J') && MinorMode(OverWrite)) {
  833. X        register int    num,
  834. X                i;
  835. X
  836. X        for (i = 0, num = arg_value(); i < num; i++) {
  837. X            int    pos = calc_pos(linebuf, curchar);
  838. X
  839. X            if (!eolp()) {
  840. X                if (linebuf[curchar] == '\t') {
  841. X                    if ((pos + 1) == ((pos + tabstop) - (pos % tabstop)))
  842. X                        del_char(FORWARD, 1);
  843. X                } else
  844. X                    del_char(FORWARD, 1);
  845. X            }
  846. X            insert_c(LastKeyStruck, 1);
  847. X        }
  848. X    } else
  849. X        Insert(LastKeyStruck);
  850. X
  851. X    if (MinorMode(Fill) && (curchar >= RMargin ||
  852. X                   (calc_pos(linebuf, curchar) >= RMargin))) {
  853. X        int margin;
  854. X        Bufpos save;
  855. X
  856. X        if (MinorMode(Indent)) {
  857. X            DOTsave(&save);
  858. X            ToIndent();
  859. X            margin = calc_pos(linebuf, curchar);
  860. X            SetDot(&save);
  861. X        } else
  862. X            margin = LMargin;
  863. X        DoJustify(curline, 0, curline,
  864. X              curchar + strlen(&linebuf[curchar]), 1, margin);
  865. X    }
  866. X}
  867. X
  868. void
  869. Insert(c)
  870. X{
  871. X    if (c == CTL('J'))
  872. X        LineInsert(arg_value());
  873. X    else
  874. X        insert_c(c, arg_value());
  875. X}
  876. X
  877. X/* insert character C N times at point */
  878. void
  879. insert_c(c, n)
  880. X{
  881. X    if (n <= 0)
  882. X        return;
  883. X    modify();
  884. X    makedirty(curline);
  885. X    ins_c(c, linebuf, curchar, n, LBSIZE);
  886. X    IFixMarks(curline, curchar, curline, curchar + n);
  887. X    curchar += n;
  888. X}    
  889. X
  890. X/* Tab in to the right place for C mode */
  891. X
  892. void
  893. Tab()
  894. X{
  895. X#ifdef LISP
  896. X    if (MajorMode(LISPMODE) && (bolp() || !eolp())) {
  897. X        int    dotchar = curchar;
  898. X        Mark    *m = 0;
  899. X
  900. X        ToIndent();
  901. X        if (dotchar > curchar)
  902. X            m = MakeMark(curline, dotchar, M_FLOATER);
  903. X        (void) lisp_indent();
  904. X        if (m) {
  905. X            ToMark(m);
  906. X            DelMark(m);
  907. X        } else
  908. X            ToIndent();
  909. X        return;
  910. X    }
  911. X#endif
  912. X    if (MajorMode(CMODE) && strlen(linebuf) == 0)
  913. X        (void) c_indent(CIndIncrmt);
  914. X    else
  915. X        SelfInsert();
  916. X}
  917. X
  918. void
  919. QuotChar()
  920. X{
  921. X    int    c,
  922. X        slow;
  923. X
  924. X    c = waitchar(&slow);
  925. X    if (slow)
  926. X        message(key_strokes);
  927. X    if (c != CTL('@'))
  928. X        Insert(c);
  929. X}
  930. X
  931. X/* Insert the paren.  If in C mode and c is a '}' then insert the
  932. X   '}' in the "right" place for C indentation; that is indented 
  933. X   the same amount as the matching '{' is indented. */
  934. X
  935. int    PDelay = 5,    /* 1/2 a second */
  936. X    CIndIncrmt = 8;
  937. X
  938. void
  939. DoParen()
  940. X{
  941. X    Bufpos    *bp = (Bufpos *) -1;
  942. X    int    nx,
  943. X        c = LastKeyStruck;
  944. X
  945. X    if (!isclosep(c)) {
  946. X        SelfInsert();
  947. X        return;
  948. X    }
  949. X
  950. X    if (MajorMode(CMODE) && c == '}' && blnkp(linebuf))
  951. X        bp = c_indent(0);
  952. X#ifdef LISP
  953. X    if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf))
  954. X        bp = lisp_indent();
  955. X#endif
  956. X    SelfInsert();
  957. X#ifdef MAC
  958. X    if (MinorMode(ShowMatch) && !in_macro()) {
  959. X#else
  960. X    if (MinorMode(ShowMatch) && !charp() && !in_macro()) {
  961. X#endif
  962. X        b_char(1);    /* Back onto the ')' */
  963. X        if ((int) bp == -1)
  964. X            bp = m_paren(c, BACKWARD, NO, YES);
  965. X        f_char(1);
  966. X        if (bp != 0) {
  967. X            nx = in_window(curwind, bp->p_line);
  968. X            if (nx != -1) {        /* is visible */
  969. X                Bufpos    b;
  970. X
  971. X                DOTsave(&b);
  972. X                SetDot(bp);
  973. X                SitFor(PDelay);
  974. X                SetDot(&b);
  975. X            } else
  976. X                s_mess("%s", lcontents(bp->p_line));
  977. X        }
  978. X        mp_error();    /* display error message */
  979. X    }
  980. X}
  981. X
  982. void
  983. LineAI()
  984. X{
  985. X    DoNewline(TRUE);
  986. X}
  987. X
  988. void
  989. Newline()
  990. X{
  991. X    DoNewline(MinorMode(Indent));
  992. X}    
  993. X
  994. void
  995. DoNewline(indentp)
  996. X{
  997. X    Bufpos    save;
  998. X    int    indent;
  999. X
  1000. X    /* first we calculate the indent of the current line */
  1001. X    DOTsave(&save);
  1002. X    ToIndent();
  1003. X    indent = calc_pos(linebuf, curchar);
  1004. X    SetDot(&save);
  1005. X
  1006. X#ifdef ABBREV
  1007. X    MaybeAbbrevExpand();
  1008. X#endif
  1009. X#ifdef LISP
  1010. X    if (MajorMode(LISPMODE))
  1011. X        DelWtSpace();
  1012. X    else
  1013. X#endif
  1014. X        if (indentp || blnkp(linebuf))
  1015. X        DelWtSpace();
  1016. X        
  1017. X    /* If there is more than 2 blank lines in a row then don't make
  1018. X       a newline, just move down one. */
  1019. X    if (arg_value() == 1 && eolp() && TwoBlank())
  1020. X        SetLine(curline->l_next);
  1021. X    else
  1022. X        LineInsert(arg_value());
  1023. X
  1024. X    if (indentp)
  1025. X#ifdef LISP
  1026. X        if (MajorMode(LISPMODE))
  1027. X        (void) lisp_indent();
  1028. X        else
  1029. X#endif
  1030. X        n_indent((LMargin == 0) ? indent : LMargin);
  1031. X}
  1032. X
  1033. void
  1034. ins_str(str, ok_nl)
  1035. register char    *str;
  1036. X{
  1037. X    register char    c;
  1038. X    Bufpos    save;
  1039. X    int    llen;
  1040. X
  1041. X    if (*str == 0)
  1042. X        return;        /* ain't nothing to insert! */
  1043. X    DOTsave(&save);
  1044. X    llen = strlen(linebuf);
  1045. X    while (c = *str++) {
  1046. X        if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) {
  1047. X            IFixMarks(save.p_line, save.p_char, curline, curchar);
  1048. X            modify();
  1049. X            makedirty(curline);
  1050. X            LineInsert(1);
  1051. X            DOTsave(&save);
  1052. X            llen = strlen(linebuf);
  1053. X        }
  1054. X        if (c != '\n') {
  1055. X            ins_c(c, linebuf, curchar++, 1, LBSIZE);
  1056. X            llen += 1;
  1057. X        }
  1058. X    }
  1059. X    IFixMarks(save.p_line, save.p_char, curline, curchar);
  1060. X    modify();
  1061. X    makedirty(curline);
  1062. X}
  1063. X
  1064. void
  1065. open_lines(n)
  1066. X{
  1067. X    Bufpos    dot;
  1068. X
  1069. X    DOTsave(&dot);
  1070. X    LineInsert(n);    /* Open the lines... */
  1071. X    SetDot(&dot);
  1072. X}
  1073. X
  1074. void
  1075. OpenLine()
  1076. X{
  1077. X    open_lines(arg_value());
  1078. X}
  1079. X
  1080. X/* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at
  1081. X   ATLINE/ATCHAR in WHATBUF. */
  1082. X
  1083. Bufpos *
  1084. DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
  1085. Line    *fline,
  1086. X    *tline,
  1087. X    *atline;
  1088. Buffer    *whatbuf;
  1089. X{
  1090. X    register Line    *newline;
  1091. X    static Bufpos    bp;
  1092. X    char    save[LBSIZE],
  1093. X        buf[LBSIZE];
  1094. X    Line    *startline = atline;
  1095. X    int    startchar = atchar;
  1096. X
  1097. X    lsave();
  1098. X    if (whatbuf)
  1099. X        modify();
  1100. X    (void) ltobuf(atline, genbuf);
  1101. X    strcpy(save, &genbuf[atchar]);
  1102. X
  1103. X    (void) ltobuf(fline, buf);
  1104. X    if (fline == tline)
  1105. X        buf[tchar] = '\0';
  1106. X
  1107. X    linecopy(genbuf, atchar, &buf[fchar]);
  1108. X    atline->l_dline = putline(genbuf);
  1109. X    makedirty(atline);
  1110. X
  1111. X    fline = fline->l_next;
  1112. X    while (fline != tline->l_next) {
  1113. X        newline = listput(whatbuf, atline);
  1114. X        newline->l_dline = fline->l_dline;
  1115. X        makedirty(newline);
  1116. X        fline = fline->l_next;
  1117. X        atline = newline;
  1118. X        atchar = 0;
  1119. X    }
  1120. X
  1121. X    getline(atline->l_dline, genbuf);
  1122. X    atchar += tchar;
  1123. X    linecopy(genbuf, atchar, save);
  1124. X    atline->l_dline = putline(genbuf);
  1125. X    makedirty(atline);
  1126. X    IFixMarks(startline, startchar, atline, atchar);
  1127. X    bp.p_line = atline;
  1128. X    bp.p_char = atchar;
  1129. X    this_cmd = YANKCMD;
  1130. X    getDOT();            /* Whatever used to be in linebuf */
  1131. X    return &bp;
  1132. X}
  1133. X
  1134. void
  1135. YankPop()
  1136. X{
  1137. X    Line    *line,
  1138. X        *last;
  1139. X    Mark    *mp = CurMark();
  1140. X    Bufpos    *dot;
  1141. X    int    dir = -1;    /* Direction to rotate the ring */
  1142. X
  1143. X    if (last_cmd != YANKCMD)
  1144. X        complain("Yank something first!");
  1145. X
  1146. X    lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar));
  1147. X
  1148. X    /* Now must find a recently killed region. */
  1149. X
  1150. X    if (arg_value() < 0)
  1151. X        dir = 1;
  1152. X
  1153. X    killptr += dir;
  1154. X    for (;;) {
  1155. X        if (killptr < 0)
  1156. X            killptr = NUMKILLS - 1;
  1157. X        else if (killptr >= NUMKILLS)
  1158. X            killptr = 0;
  1159. X        if (killbuf[killptr])
  1160. X            break;
  1161. X        killptr += dir;
  1162. X    }
  1163. X
  1164. X    this_cmd = YANKCMD;
  1165. X
  1166. X    line = killbuf[killptr];
  1167. X    last = lastline(line);
  1168. X    dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf);
  1169. X    MarkSet(CurMark(), curline, curchar);
  1170. X    SetDot(dot);
  1171. X}
  1172. X
  1173. X/* This is an attempt to reduce the amount of memory taken up by each line.
  1174. X   Without this each malloc of a line uses sizeof (line) + sizeof(HEADER)
  1175. X   where line is 3 words and HEADER is 1 word.
  1176. X   This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line)
  1177. X   and divide each chuck into lineS.  A line is free in a chunk when its
  1178. X   line->l_dline == 0, so freeline sets dline to 0. */
  1179. X
  1180. X#define CHUNKSIZE    300
  1181. X
  1182. struct chunk {
  1183. X    int    c_nlines;    /* Number of lines in this chunk (so they
  1184. X                   don't all have to be CHUNKSIZE long). */
  1185. X    Line    *c_block;    /* Chunk of memory */
  1186. X    struct chunk    *c_nextfree;    /* Next chunk of lines */
  1187. X};
  1188. X
  1189. private struct chunk    *fchunk = 0;
  1190. private Line    *ffline = 0;    /* First free line */
  1191. X
  1192. void
  1193. freeline(line)
  1194. register Line    *line;
  1195. X{
  1196. X    line->l_dline = 0;
  1197. X    line->l_next = ffline;
  1198. X    if (ffline)
  1199. X        ffline->l_prev = line;
  1200. X    line->l_prev = 0;
  1201. X    ffline = line;
  1202. X}
  1203. X
  1204. void
  1205. lfreelist(first)
  1206. register Line    *first;
  1207. X{
  1208. X    if (first)
  1209. X        lfreereg(first, lastline(first));
  1210. X}
  1211. X
  1212. X/* Append region from line1 to line2 onto the free list of lines */
  1213. X
  1214. void
  1215. lfreereg(line1, line2)
  1216. register Line    *line1,
  1217. X        *line2;
  1218. X{
  1219. X    register Line    *next,
  1220. X            *last = line2->l_next;
  1221. X
  1222. X    while (line1 != last) {
  1223. X        next = line1->l_next;
  1224. X        freeline(line1);
  1225. X        line1 = next;
  1226. X    }
  1227. X}
  1228. X
  1229. private int
  1230. newchunk()
  1231. X{
  1232. X    register Line    *newline;
  1233. X    register int    i;
  1234. X    struct chunk    *f;
  1235. X    int    nlines = CHUNKSIZE;
  1236. X
  1237. X    f = (struct chunk *) emalloc(sizeof (struct chunk));
  1238. X    if (f == 0)
  1239. X        return 0;
  1240. X
  1241. X    if ((f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines))) == 0) {
  1242. X        while (nlines > 0) {
  1243. X            f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines));
  1244. X            if (f->c_block != 0)
  1245. X                break;
  1246. X            nlines /= 2;
  1247. X        }
  1248. X    }
  1249. X
  1250. X    if (nlines <= 0)
  1251. X        return 0;
  1252. X
  1253. X    f->c_nlines = nlines;
  1254. X    for (i = 0, newline = f->c_block; i < nlines; newline++, i++)
  1255. X        freeline(newline);
  1256. X    f->c_nextfree = fchunk;
  1257. X    fchunk = f;
  1258. X    return 1;
  1259. X}
  1260. X
  1261. X/* New BUFfer LINE */
  1262. X
  1263. Line *
  1264. nbufline()
  1265. X{
  1266. X    register Line    *newline;
  1267. X
  1268. X    if (ffline == 0)    /* No free list */
  1269. X        if (newchunk() == 0)
  1270. X            complain("[Out of lines] ");
  1271. X    newline = ffline;
  1272. X    ffline = ffline->l_next;
  1273. X    if (ffline)
  1274. X        ffline->l_prev = 0;
  1275. X    return newline;
  1276. X}
  1277. X
  1278. X/* Remove the free lines, in chunk c, from the free list because they are
  1279. X   no longer free. */
  1280. X
  1281. private void
  1282. remfreelines(c)
  1283. register struct chunk    *c;
  1284. X{
  1285. X    register Line    *lp;
  1286. X    register int    i;
  1287. X
  1288. X    for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) {
  1289. X        if (lp->l_prev)
  1290. X            lp->l_prev->l_next = lp->l_next;
  1291. X        else
  1292. X            ffline = lp->l_next;
  1293. X        if (lp->l_next)
  1294. X            lp->l_next->l_prev = lp->l_prev;
  1295. X    }
  1296. X}
  1297. X
  1298. X/* This is used to garbage collect the chunks of lines when malloc fails
  1299. X   and we are NOT looking for a new buffer line.  This goes through each
  1300. X   chunk, and if every line in a given chunk is not allocated, the entire
  1301. X   chunk is `free'd by "free()". */
  1302. X
  1303. void
  1304. GCchunks()
  1305. X{
  1306. X    register struct chunk    *cp;
  1307. X    struct chunk    *prev = 0,
  1308. X            *next = 0;
  1309. X    register int    i;
  1310. X    register Line    *newline;
  1311. X
  1312. X     for (cp = fchunk; cp != 0; cp = next) {
  1313. X        for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++)
  1314. X            if (newline->l_dline != 0)
  1315. X                break;
  1316. X
  1317. X         next = cp->c_nextfree;
  1318. X
  1319. X        if (i == cp->c_nlines) {        /* Unlink it!!! */
  1320. X            if (prev)
  1321. X                prev->c_nextfree = cp->c_nextfree;
  1322. X            else
  1323. X                fchunk = cp->c_nextfree;
  1324. X            remfreelines(cp);
  1325. X            free((char *) cp->c_block);
  1326. X            free((char *) cp);
  1327. X        } else
  1328. X            prev = cp;
  1329. X    }
  1330. X}
  1331. X
  1332. X#ifdef LISP
  1333. X
  1334. X/* Grind S-Expr */
  1335. X
  1336. void
  1337. GSexpr()
  1338. X{
  1339. X    Bufpos    dot,
  1340. X        end;
  1341. X
  1342. X    if (linebuf[curchar] != '(')
  1343. X        complain((char *) 0);
  1344. X    DOTsave(&dot);
  1345. X    FSexpr();
  1346. X    DOTsave(&end);
  1347. X    SetDot(&dot);
  1348. X    for (;;) {
  1349. X        if (curline == end.p_line)
  1350. X            break;
  1351. X        line_move(FORWARD, 1, NO);
  1352. X        if (!blnkp(linebuf))
  1353. X            (void) lisp_indent();
  1354. X    }
  1355. X    SetDot(&dot);
  1356. X}
  1357. X
  1358. X/* lisp_indent() indents a new line in Lisp Mode, according to where
  1359. X   the matching close-paren would go if we typed that (sort of). */
  1360. X
  1361. private Table    *specials = NIL;
  1362. X
  1363. private void
  1364. init_specials()
  1365. X{
  1366. X    static char *words[] = {
  1367. X        "case",
  1368. X        "def",
  1369. X        "dolist",
  1370. X        "fluid-let",
  1371. X        "lambda",
  1372. X        "let",
  1373. X        "lexpr",
  1374. X        "macro",
  1375. X        "named-l",    /* named-let and named-lambda */
  1376. X        "nlambda",
  1377. X        "prog",
  1378. X        "selectq",
  1379. X        0
  1380. X    };
  1381. X    char    **wordp = words;
  1382. X
  1383. X    specials = make_table();
  1384. X    while (*wordp)
  1385. X        add_word(*wordp++, specials);
  1386. X}
  1387. X
  1388. void
  1389. AddSpecial()
  1390. X{
  1391. X    char    *word;
  1392. X
  1393. X    word = ask((char *) 0, ProcFmt);
  1394. X    if (specials == NIL)
  1395. X        init_specials();
  1396. X    add_word(copystr(word), specials);
  1397. X}
  1398. X
  1399. Bufpos *
  1400. lisp_indent()
  1401. X{
  1402. X    Bufpos    *bp,
  1403. X        savedot;
  1404. X    int    goal;
  1405. X
  1406. X    bp = m_paren(')', BACKWARD, NO, YES);
  1407. X
  1408. X    if (bp == 0)
  1409. X        return 0;
  1410. X
  1411. X    /* We want to end up
  1412. X     
  1413. X         (atom atom atom ...
  1414. X               ^ here.
  1415. X     */
  1416. X
  1417. X    DOTsave(&savedot);
  1418. X    SetDot(bp);
  1419. X    f_char(1);
  1420. X    if (linebuf[curchar] != '(') {
  1421. X        register Word    *wp;
  1422. X
  1423. X        if (specials == NIL)
  1424. X            init_specials();
  1425. X        for (wp = table_top(specials); wp != NIL; wp = next_word(wp))
  1426. X            if (casencmp(word_text(wp), &linebuf[curchar], word_length(wp)) == 0)
  1427. X                break;
  1428. X        if (wp == NIL) {    /* not special */
  1429. X            int    c_char = curchar;
  1430. X
  1431. X            WITH_TABLE(curbuf->b_major)
  1432. X                f_word(1);
  1433. X            END_TABLE();
  1434. X            if (LookingAt("[ \t]*;\\|[ \t]*$", linebuf, curchar))
  1435. X                curchar = c_char;
  1436. X            else while (linebuf[curchar] == ' ')
  1437. X                curchar += 1;
  1438. X        } else
  1439. X            curchar += 1;
  1440. X    }
  1441. X    goal = calc_pos(linebuf, curchar);
  1442. X    SetDot(&savedot);
  1443. X    n_indent(goal);
  1444. X
  1445. X    return bp;
  1446. X}
  1447. X#endif /* LISP */
  1448. END_OF_FILE
  1449. if test 14465 -ne `wc -c <'./insert.c'`; then
  1450.     echo shar: \"'./insert.c'\" unpacked with wrong size!
  1451. fi
  1452. # end of './insert.c'
  1453. fi
  1454. if test -f './recover.c' -a "${1}" != "-c" ; then 
  1455.   echo shar: Will not clobber existing file \"'./recover.c'\"
  1456. else
  1457. echo shar: Extracting \"'./recover.c'\" \(14306 characters\)
  1458. sed "s/^X//" >'./recover.c' <<'END_OF_FILE'
  1459. X/***************************************************************************
  1460. X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  1461. X * is provided to you without charge, and with no warranty.  You may give  *
  1462. X * away copies of JOVE, including sources, provided that this notice is    *
  1463. X * included in all the files.                                              *
  1464. X ***************************************************************************/
  1465. X
  1466. X/* Recovers JOVE files after a system/editor crash.
  1467. X   Usage: recover [-d directory] [-syscrash]
  1468. X   The -syscrash option is specified in /etc/rc and what it does is
  1469. X   move all the jove tmp files from TMP_DIR to REC_DIR.
  1470. X
  1471. X   The -d option lets you specify the directory to search for tmp files when
  1472. X   the default isn't the right one.
  1473. X
  1474. X   Look in Makefile to change the default directories. */
  1475. X
  1476. X#include <stdio.h>    /* Do stdio first so it doesn't override OUR
  1477. X               definitions. */
  1478. X#undef EOF
  1479. X#undef BUFSIZ
  1480. X#undef putchar
  1481. X#undef getchar
  1482. X
  1483. X#define STDIO
  1484. X
  1485. X#include "jove.h"
  1486. X#include "temp.h"
  1487. X#include "rec.h"
  1488. X#include <signal.h>
  1489. X#include <sys/file.h>
  1490. X#include <sys/stat.h>
  1491. X#include <sys/dir.h>
  1492. X
  1493. X#ifndef L_SET
  1494. X#    define L_SET    0
  1495. X#    define L_INCR    1
  1496. X#endif
  1497. X
  1498. char    blk_buf[BUFSIZ];
  1499. int    nleft;
  1500. FILE    *ptrs_fp;
  1501. int    data_fd;
  1502. struct rec_head    Header;
  1503. char    datafile[40],
  1504. X    pntrfile[40];
  1505. long    Nchars,
  1506. X    Nlines;
  1507. char    tty[] = "/dev/tty";
  1508. int    UserID,
  1509. X    Verbose = 0;
  1510. char    *Directory = 0;        /* the directory we're looking in */
  1511. X
  1512. struct file_pair {
  1513. X    char    *file_data,
  1514. X        *file_rec;
  1515. X#define INSPECTED    01
  1516. X    int    file_flags;
  1517. X    struct file_pair    *file_next;
  1518. X} *First = 0,
  1519. X  *Last = 0;
  1520. X
  1521. struct rec_entry    *buflist[100] = {0};
  1522. X
  1523. X#ifndef BSD4_2
  1524. X
  1525. typedef struct {
  1526. X    int    d_fd;        /* File descriptor for this directory */
  1527. X} DIR;
  1528. X
  1529. DIR *
  1530. opendir(dir)
  1531. char    *dir;
  1532. X{
  1533. X    DIR    *dp = (DIR *) malloc(sizeof *dp);
  1534. X
  1535. X    if ((dp->d_fd = open(dir, 0)) == -1)
  1536. X        return NULL;
  1537. X    return dp;
  1538. X}
  1539. X
  1540. closedir(dp)
  1541. DIR    *dp;
  1542. X{
  1543. X    (void) close(dp->d_fd);
  1544. X    free(dp);
  1545. X}
  1546. X
  1547. struct direct *
  1548. readdir(dp)
  1549. DIR    *dp;
  1550. X{
  1551. X    static struct direct    dir;
  1552. X
  1553. X    do
  1554. X        if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
  1555. X            return NULL;
  1556. X#if defined(elxsi) && defined(SYSV)
  1557. X    /*
  1558. X     * Elxsi has a BSD4.2 implementation which may or may not use
  1559. X     * `twisted inodes' ...  Anyone able to check?
  1560. X     */
  1561. X    while (*(unsigned short *)&dir.d_ino == 0);
  1562. X#else
  1563. X    while (dir.d_ino == 0);
  1564. X#endif
  1565. X
  1566. X    return &dir;
  1567. X}
  1568. X
  1569. X#endif /* BSD4_2 */
  1570. X
  1571. X/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
  1572. X   long. */
  1573. X
  1574. getline(tl, buf)
  1575. disk_line    tl;
  1576. char    *buf;
  1577. X{
  1578. X    register char    *bp,
  1579. X            *lp;
  1580. X    register int    nl;
  1581. X    char    *getblock();
  1582. X
  1583. X    lp = buf;
  1584. X    bp = getblock(tl >> 1);
  1585. X    nl = nleft;
  1586. X    tl = blk_round(tl);
  1587. X
  1588. X    while (*lp++ = *bp++) {
  1589. X        if (--nl == 0) {
  1590. X            tl = forward_block(tl);
  1591. X            bp = getblock(tl >> 1);
  1592. X            nl = nleft;
  1593. X        }
  1594. X    }
  1595. X}
  1596. X
  1597. char *
  1598. getblock(atl)
  1599. disk_line    atl;
  1600. X{
  1601. X    int    bno,
  1602. X        off;
  1603. X    static int    curblock = -1;
  1604. X
  1605. X    bno = da_to_bno(atl);
  1606. X    off = da_to_off(atl);
  1607. X    nleft = BUFSIZ - off;
  1608. X
  1609. X    if (bno != curblock) {
  1610. X        lseek(data_fd, (long) bno * BUFSIZ, L_SET);
  1611. X        read(data_fd, blk_buf, BUFSIZ);
  1612. X        curblock = bno;
  1613. X    }
  1614. X    return blk_buf + off;
  1615. X}
  1616. X
  1617. char *
  1618. copystr(s)
  1619. char    *s;
  1620. X{
  1621. X    char    *str;
  1622. X
  1623. X    str = malloc(strlen(s) + 1);
  1624. X    strcpy(str, s);
  1625. X
  1626. X    return str;
  1627. X}
  1628. X
  1629. X/* Scandir returns the number of entries or -1 if the directory cannoot
  1630. X   be opened or malloc fails. */
  1631. X
  1632. scandir(dir, nmptr, qualify, sorter)
  1633. char    *dir;
  1634. struct direct    ***nmptr;
  1635. int    (*qualify)();
  1636. struct direct    *(*sorter)();
  1637. X{
  1638. X    DIR    *dirp;
  1639. X    struct direct    *entry,
  1640. X            **ourarray;
  1641. X    int    nalloc = 10,
  1642. X        nentries = 0;
  1643. X
  1644. X    if ((dirp = opendir(dir)) == NULL)
  1645. X        return -1;
  1646. X    ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *));
  1647. X    while ((entry = readdir(dirp)) != NULL) {
  1648. X        if (qualify != 0 && (*qualify)(entry) == 0)
  1649. X            continue;
  1650. X        if (nentries == nalloc) {
  1651. X            ourarray = (struct direct **) realloc(ourarray, (nalloc += 10) * sizeof (struct direct));
  1652. X            if (ourarray == NULL)
  1653. X                return -1;
  1654. X        }
  1655. X        ourarray[nentries] = (struct direct *) malloc(sizeof *entry);
  1656. X        *ourarray[nentries] = *entry;
  1657. X        nentries += 1;
  1658. X    }
  1659. X    closedir(dirp);
  1660. X    if (nentries != nalloc)
  1661. X        ourarray = (struct direct **) realloc(ourarray,
  1662. X                    (nentries * sizeof (struct direct)));
  1663. X    if (sorter != 0)
  1664. X        qsort(ourarray, nentries, sizeof (struct direct **), sorter);
  1665. X    *nmptr = ourarray;
  1666. X
  1667. X    return nentries;
  1668. X}
  1669. X
  1670. alphacomp(a, b)
  1671. struct direct    **a,
  1672. X        **b;
  1673. X{
  1674. X    return strcmp((*a)->d_name, (*b)->d_name);
  1675. X}
  1676. X
  1677. char    *CurDir;
  1678. X
  1679. X/* Scan the DIRNAME directory for jove tmp files, and make a linked list
  1680. X   out of them. */
  1681. X
  1682. get_files(dirname)
  1683. char    *dirname;
  1684. X{
  1685. X    int    add_name();
  1686. X    struct direct    **nmptr;
  1687. X
  1688. X    CurDir = dirname;
  1689. X    scandir(dirname, &nmptr, add_name, (int (*)())0);
  1690. X}
  1691. X
  1692. add_name(dp)
  1693. struct direct    *dp;
  1694. X{
  1695. X    char    dfile[128],
  1696. X        rfile[128];
  1697. X    struct file_pair    *fp;
  1698. X    struct rec_head        header;
  1699. X    int    fd;
  1700. X
  1701. X    if (strncmp(dp->d_name, "jrec", 4) != 0)
  1702. X        return 0;
  1703. X    /* If we get here, we found a "recover" tmp file, so now
  1704. X       we look for the corresponding "data" tmp file.  First,
  1705. X       though, we check to see whether there is anything in
  1706. X       the "recover" file.  If it's 0 length, there's no point
  1707. X       in saving its name. */
  1708. X    (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name);
  1709. X    (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + 4);
  1710. X    if ((fd = open(rfile, 0)) != -1) {
  1711. X        if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
  1712. X            close(fd);
  1713. X                return 0;
  1714. X        } else
  1715. X            close(fd);
  1716. X    }
  1717. X    if (access(dfile, 0) != 0) {
  1718. X        fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, dp->d_name);
  1719. X        fprintf(stderr, "so deleting...\n");
  1720. X        (void) unlink(rfile);
  1721. X        (void) unlink(dfile);
  1722. X        return 0;
  1723. X    }
  1724. X    /* If we get here, we've found both files, so we put them
  1725. X       in the list. */
  1726. X    fp = (struct file_pair *) malloc (sizeof *fp);
  1727. X    if ((char *) fp == 0) {
  1728. X        fprintf(stderr, "recover: cannot malloc for file_pair.\n");
  1729. X        exit(-1);
  1730. X    }
  1731. X    fp->file_data = copystr(dfile);
  1732. X    fp->file_rec = copystr(rfile);
  1733. X    fp->file_flags = 0;
  1734. X    fp->file_next = First;
  1735. X    First = fp;
  1736. X
  1737. X    return 1;
  1738. X}
  1739. X
  1740. options()
  1741. X{
  1742. X    printf("Options are:\n");
  1743. X    printf("    ?        list options.\n");
  1744. X    printf("    get        get a buffer to a file.\n");
  1745. X    printf("    list        list known buffers.\n");
  1746. X    printf("    print        print a buffer to terminal.\n");
  1747. X    printf("    quit        quit and delete jove tmp files.\n");
  1748. X    printf("    restore        restore all buffers.\n");
  1749. X}
  1750. X
  1751. X/* Returns a legitimate buffer # */
  1752. X
  1753. struct rec_entry **
  1754. getsrc()
  1755. X{
  1756. X    char    name[128];
  1757. X    int    number;
  1758. X
  1759. X    for (;;) {
  1760. X        tellme("Which buffer ('?' for list)? ", name);
  1761. X        if (name[0] == '?')
  1762. X            list();
  1763. X        else if (name[0] == '\0')
  1764. X            return 0;
  1765. X        else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
  1766. X            return &buflist[number];
  1767. X        else {
  1768. X            int    i;
  1769. X
  1770. X            for (i = 1; i <= Header.Nbuffers; i++)
  1771. X                if (strcmp(buflist[i]->r_bname, name) == 0)
  1772. X                    return &buflist[i];
  1773. X            printf("%s: unknown buffer.\n", name);
  1774. X        }
  1775. X    }
  1776. X}
  1777. X
  1778. X/* Get a destination file name. */
  1779. X
  1780. static char *
  1781. getdest()
  1782. X{
  1783. X    static char    filebuf[256];
  1784. X
  1785. X    tellme("Output file: ", filebuf);
  1786. X    if (filebuf[0] == '\0')
  1787. X        return 0;
  1788. X    return filebuf;
  1789. X}
  1790. X
  1791. X#include "ctype.h"
  1792. X
  1793. char *
  1794. readword(buf)
  1795. char    *buf;
  1796. X{
  1797. X    int    c;
  1798. X    char    *bp = buf;
  1799. X
  1800. X    while (index(" \t\n", c = getchar()))
  1801. X        ;
  1802. X
  1803. X    do {
  1804. X        if (index(" \t\n", c))
  1805. X            break;
  1806. X        *bp++ = c;
  1807. X    } while ((c = getchar()) != EOF);
  1808. X    *bp = 0;
  1809. X
  1810. X    return buf;
  1811. X}
  1812. X
  1813. tellme(quest, answer)
  1814. char    *quest,
  1815. X    *answer;
  1816. X{
  1817. X    if (stdin->_cnt <= 0) {
  1818. X        printf("%s", quest);
  1819. X        fflush(stdout);
  1820. X    }
  1821. X    readword(answer);
  1822. X}
  1823. X
  1824. X/* Print the specified file to strandard output. */
  1825. X
  1826. jmp_buf    int_env;
  1827. X
  1828. catch()
  1829. X{
  1830. X    longjmp(int_env, 1);
  1831. X}
  1832. X
  1833. restore()
  1834. X{
  1835. X    register int    i;
  1836. X    char    tofile[100],
  1837. X        answer[30];
  1838. X    int    nrecovered = 0;
  1839. X
  1840. X    for (i = 1; i <= Header.Nbuffers; i++) {
  1841. X        (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
  1842. tryagain:
  1843. X        printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
  1844. X                             tofile);
  1845. X        tellme(" ", answer);
  1846. X        switch (answer[0]) {
  1847. X        case 'y':
  1848. X            break;
  1849. X
  1850. X        case 'n':
  1851. X            continue;
  1852. X
  1853. X        default:
  1854. X            tellme("What file should I use instead? ", tofile);
  1855. X            goto tryagain;
  1856. X        }
  1857. X        get(&buflist[i], tofile);
  1858. X        nrecovered += 1;
  1859. X    }
  1860. X    printf("Recovered %d buffers.\n", nrecovered);
  1861. X}
  1862. X
  1863. get(src, dest)
  1864. struct rec_entry    **src;
  1865. char    *dest;
  1866. X{
  1867. X    FILE    *outfile;
  1868. X
  1869. X    if (src == 0 || dest == 0)
  1870. X        return;
  1871. X    (void) signal(SIGINT, catch);
  1872. X    if (setjmp(int_env) == 0) {
  1873. X        if ((outfile = fopen(dest, "w")) == NULL) {
  1874. X            printf("recover: cannot create %s.\n", dest);
  1875. X            return;
  1876. X        }
  1877. X        if (dest != tty)
  1878. X            printf("\"%s\"", dest);
  1879. X        dump_file(src - buflist, outfile);
  1880. X    } else
  1881. X        printf("\nAborted!\n");
  1882. X    fclose(outfile);
  1883. X    if (dest != tty)
  1884. X        printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
  1885. X    (void) signal(SIGINT, SIG_DFL);
  1886. X}
  1887. X
  1888. char **
  1889. scanvec(args, str)
  1890. register char    **args,
  1891. X        *str;
  1892. X{
  1893. X    while (*args) {
  1894. X        if (strcmp(*args, str) == 0)
  1895. X            return args;
  1896. X        args += 1;
  1897. X    }
  1898. X    return 0;
  1899. X}
  1900. X
  1901. read_rec(recptr)
  1902. struct rec_entry    *recptr;
  1903. X{
  1904. X    if (fread((char *) recptr, sizeof *recptr, 1, ptrs_fp) != 1)
  1905. X        fprintf(stderr, "recover: cannot read record.\n");
  1906. X}
  1907. X
  1908. seekto(which)
  1909. X{
  1910. X    struct rec_entry    rec;
  1911. X    long    offset;
  1912. X    int    i;
  1913. X
  1914. X    offset = sizeof (Header) + (Header.Nbuffers * sizeof (rec));
  1915. X    for (i = 1; i < which; i++)
  1916. X        offset += buflist[i]->r_nlines * sizeof (disk_line);
  1917. X    fseek(ptrs_fp, offset, L_SET);
  1918. X}
  1919. X
  1920. makblist()
  1921. X{
  1922. X    int    i;
  1923. X
  1924. X    fseek(ptrs_fp, (long) sizeof (Header), L_SET);
  1925. X    for (i = 1; i <= Header.Nbuffers; i++) {
  1926. X        if (buflist[i] == 0)
  1927. X            buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
  1928. X        read_rec(buflist[i]);
  1929. X    }
  1930. X    while (buflist[i]) {
  1931. X        free((char *) buflist[i]);
  1932. X        buflist[i] = 0;
  1933. X        i += 1;
  1934. X    }
  1935. X}
  1936. X
  1937. disk_line
  1938. getaddr(fp)
  1939. register FILE    *fp;
  1940. X{
  1941. X    register int    nchars = sizeof (disk_line);
  1942. X    disk_line    addr;
  1943. X    register char    *cp = (char *) &addr;
  1944. X
  1945. X    while (--nchars >= 0)
  1946. X        *cp++ = getc(fp);
  1947. X
  1948. X    return addr;
  1949. X}
  1950. X
  1951. dump_file(which, out)
  1952. FILE    *out;
  1953. X{
  1954. X    register int    nlines;
  1955. X    register disk_line    daddr;
  1956. X    char    buf[BUFSIZ];
  1957. X
  1958. X    seekto(which);
  1959. X    nlines = buflist[which]->r_nlines;
  1960. X    Nchars = Nlines = 0L;
  1961. X    while (--nlines >= 0) {
  1962. X        daddr = getaddr(ptrs_fp);
  1963. X        getline(daddr, buf);
  1964. X        Nlines += 1;
  1965. X        Nchars += 1 + strlen(buf);
  1966. X        fputs(buf, out);
  1967. X        if (nlines > 0)
  1968. X            fputc('\n', out);
  1969. X    }
  1970. X    if (out != stdout)
  1971. X        fclose(out);
  1972. X}
  1973. X
  1974. X/* List all the buffers. */
  1975. X
  1976. list()
  1977. X{
  1978. X    int    i;
  1979. X
  1980. X    for (i = 1; i <= Header.Nbuffers; i++)
  1981. X        printf("%d) buffer %s  \"%s\" (%d lines)\n", i,
  1982. X            buflist[i]->r_bname,
  1983. X            buflist[i]->r_fname,
  1984. X            buflist[i]->r_nlines);
  1985. X}
  1986. X
  1987. doit(fp)
  1988. struct file_pair    *fp;
  1989. X{
  1990. X    char    answer[30];
  1991. X    char    *datafile = fp->file_data,
  1992. X        *pntrfile = fp->file_rec;
  1993. X
  1994. X    ptrs_fp = fopen(pntrfile, "r");
  1995. X    if (ptrs_fp == NULL) {
  1996. X        if (Verbose)
  1997. X            fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
  1998. X        return 0;
  1999. X    }
  2000. X    fread((char *) &Header, sizeof Header, 1, ptrs_fp);
  2001. X    if (Header.Uid != UserID)
  2002. X        return 0;
  2003. X
  2004. X    /* Don't ask about JOVE's that are still running ... */
  2005. X#ifdef KILL0
  2006. X    if (kill(Header.Pid, 0) == 0)
  2007. X        return 0;
  2008. X#endif /* KILL0 */
  2009. X
  2010. X    if (Header.Nbuffers == 0) {
  2011. X        printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
  2012. X        ask_del(" ", fp);
  2013. X        return 1;
  2014. X    }
  2015. X        
  2016. X    if (Header.Nbuffers < 0) {
  2017. X        fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
  2018. X        ask_del("Should I delete it? ", fp);
  2019. X        return 1;    /* We'll, we sort of found something. */
  2020. X    }
  2021. X    printf("Found %d buffer%s last updated: %s",
  2022. X        Header.Nbuffers,
  2023. X        Header.Nbuffers != 1 ? "s" : "",
  2024. X        ctime(&Header.UpdTime));
  2025. X    data_fd = open(datafile, 0);
  2026. X    if (data_fd == -1) {
  2027. X        fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
  2028. X        ask_del("Should I delete the tmp files? ", fp);
  2029. X        return 1;
  2030. X    }
  2031. X    makblist();
  2032. X    list();
  2033. X
  2034. X    for (;;) {
  2035. X        tellme("(Type '?' for options): ", answer);
  2036. X        switch (answer[0]) {
  2037. X        case '\0':
  2038. X            continue;
  2039. X
  2040. X        case '?':
  2041. X            options();
  2042. X            break;
  2043. X
  2044. X        case 'l':
  2045. X            list();
  2046. X            break;
  2047. X
  2048. X        case 'p':
  2049. X            get(getsrc(), tty);
  2050. X            break;
  2051. X
  2052. X        case 'q':
  2053. X            ask_del("Shall I delete the tmp files? ", fp);
  2054. X            return 1;
  2055. X
  2056. X        case 'g':
  2057. X            {    /* So it asks for src first. */
  2058. X                char    *dest;
  2059. X                struct rec_entry    **src;
  2060. X
  2061. X                if ((src = getsrc()) == 0)
  2062. X                    break;
  2063. X                dest = getdest();
  2064. X            get(src, dest);
  2065. X            break;
  2066. X            }
  2067. X
  2068. X        case 'r':
  2069. X            restore();
  2070. X            break;
  2071. X
  2072. X        default:
  2073. X            printf("I don't know how to \"%s\"!\n", answer);
  2074. X            break;
  2075. X        }
  2076. X    }
  2077. X}
  2078. X
  2079. ask_del(prompt, fp)
  2080. char    *prompt;
  2081. struct file_pair    *fp;
  2082. X{
  2083. X    char    yorn[20];
  2084. X
  2085. X    tellme(prompt, yorn);
  2086. X    if (yorn[0] == 'y')
  2087. X        del_files(fp);
  2088. X}
  2089. X
  2090. del_files(fp)
  2091. struct file_pair    *fp;
  2092. X{
  2093. X    (void) unlink(fp->file_data);
  2094. X    (void) unlink(fp->file_rec);
  2095. X}
  2096. X
  2097. X#ifdef notdef
  2098. savetmps()
  2099. X{
  2100. X    struct file_pair    *fp;
  2101. X    int    status,
  2102. X        pid;
  2103. X
  2104. X    if (strcmp(TMP_DIR, REC_DIR) == 0)
  2105. X        return;        /* Files are moved to the same place. */
  2106. X    get_files(TMP_DIR);
  2107. X    for (fp = First; fp != 0; fp = fp->file_next) {
  2108. X        switch (pid = fork()) {
  2109. X        case -1:
  2110. X            fprintf(stderr, "recover: can't fork\n!");
  2111. X            exit(-1);
  2112. X
  2113. X        case 0:
  2114. X            execl("/bin/cp", "cp", fp->file_data, fp->file_rec, 
  2115. X                  REC_DIR, (char *)0);
  2116. X            fprintf(stderr, "recover: cannot execl /bin/cp.\n");
  2117. X            exit(-1);
  2118. X
  2119. X        default:
  2120. X            while (wait(&status) != pid)
  2121. X                ;
  2122. X            if (status != 0)
  2123. X                fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status);
  2124. X        }
  2125. X    }
  2126. X}
  2127. X#endif
  2128. X
  2129. lookup(dir)
  2130. char    *dir;
  2131. X{
  2132. X    struct file_pair    *fp;
  2133. X    struct rec_head        header;
  2134. X    char    yorn[20];
  2135. X    int    nfound = 0,
  2136. X        this_one;
  2137. X
  2138. X    printf("Checking %s ...\n", dir);
  2139. X    Directory = dir;
  2140. X    get_files(dir);
  2141. X    for (fp = First; fp != 0; fp = fp->file_next) {
  2142. X        nfound += doit(fp);
  2143. X        if (ptrs_fp)
  2144. X            (void) fclose(ptrs_fp);
  2145. X        if (data_fd > 0)
  2146. X            (void) close(data_fd);
  2147. X    }
  2148. X    return nfound;
  2149. X}
  2150. X
  2151. main(argc, argv)
  2152. int    argc;
  2153. char    *argv[];
  2154. X{
  2155. X    int    nfound;
  2156. X    char    **argvp;
  2157. X
  2158. X    UserID = getuid();
  2159. X
  2160. X    if (scanvec(argv, "-help")) {
  2161. X        printf("recover: usage: recover [-d directory]\n");
  2162. X        printf("Use \"recover\" after JOVE has died for some\n");
  2163. X        printf("unknown reason.\n\n");
  2164. X/*        printf("Use \"recover -syscrash\" when the system is in the process\n");
  2165. X        printf("of rebooting.  This is done automatically at reboot time\n");
  2166. X        printf("and so most of you don't have to worry about that.\n\n");
  2167. X */
  2168. X        printf("Use \"recover -d directory\" when the tmp files are store\n");
  2169. X        printf("in DIRECTORY instead of the default one (/tmp).\n");
  2170. X        exit(0);
  2171. X    }
  2172. X    if (scanvec(argv, "-v"))
  2173. X        Verbose = YES;
  2174. X/*    if (scanvec(argv, "-syscrash")) {
  2175. X        printf("Recovering jove files ... ");
  2176. X        savetmps();
  2177. X        printf("Done.\n");
  2178. X        exit(0);
  2179. X    } */
  2180. X    if (argvp = scanvec(argv, "-uid"))
  2181. X        UserID = atoi(argvp[1]);
  2182. X    if (argvp = scanvec(argv, "-d"))
  2183. X        nfound = lookup(argvp[1]);
  2184. X    else
  2185. X        nfound = lookup(TmpFilePath);
  2186. X    if (nfound == 0)
  2187. X        printf("There's nothing to recover.\n");
  2188. X}
  2189. END_OF_FILE
  2190. if test 14306 -ne `wc -c <'./recover.c'`; then
  2191.     echo shar: \"'./recover.c'\" unpacked with wrong size!
  2192. fi
  2193. # end of './recover.c'
  2194. fi
  2195. echo shar: End of archive 7 \(of 21\).
  2196. cp /dev/null ark7isdone
  2197. MISSING=""
  2198. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  2199.     if test ! -f ark${I}isdone ; then
  2200.     MISSING="${MISSING} ${I}"
  2201.     fi
  2202. done
  2203. if test "${MISSING}" = "" ; then
  2204.     echo You have unpacked all 21 archives.
  2205.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2206. else
  2207.     echo You still need to unpack the following archives:
  2208.     echo "        " ${MISSING}
  2209. fi
  2210. ##  End of shell archive.
  2211. exit 0
  2212.